/*     */ package com.zimbra.cs.mime;
/*     */ 
/*     */ import com.google.common.base.Joiner;
/*     */ import com.zimbra.common.mailbox.ContactConstants;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Arrays;
/*     */ import java.util.HashMap;
/*     */ import java.util.HashSet;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class ParsedAddress
/*     */   implements Comparable<ParsedAddress>
/*     */ {
/*     */   public String emailPart;
/*     */   public String personalPart;
/*     */   public String honorific;
/*     */   public String firstName;
/*     */   public String middleName;
/*     */   public String lastName;
/*     */   public String suffix;
/*  45 */   private boolean parsed = false;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  51 */   private boolean nameFormatLastFirst = false;
/*     */   
/*     */   public ParsedAddress(String address) {
/*  54 */     com.zimbra.common.mime.InternetAddress ia = new com.zimbra.common.mime.InternetAddress(address);
/*  55 */     initialize(ia.getAddress(), ia.getPersonal());
/*     */   }
/*     */   
/*     */   public ParsedAddress(com.zimbra.common.mime.InternetAddress ia) {
/*  59 */     initialize(ia.getAddress(), ia.getPersonal());
/*     */   }
/*     */   
/*     */   public ParsedAddress(javax.mail.internet.InternetAddress ia) {
/*  63 */     initialize(ia.getAddress(), ia.getPersonal());
/*     */   }
/*     */   
/*     */   public ParsedAddress(String email, String personal) {
/*  67 */     initialize(email, personal);
/*     */   }
/*     */   
/*     */   public ParsedAddress(ParsedAddress node) {
/*  71 */     this.emailPart = node.emailPart;
/*  72 */     this.personalPart = node.personalPart;
/*  73 */     this.honorific = node.honorific;
/*  74 */     this.firstName = node.firstName;
/*  75 */     this.middleName = node.middleName;
/*  76 */     this.lastName = node.lastName;
/*  77 */     this.suffix = node.suffix;
/*  78 */     this.parsed = node.parsed;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public ParsedAddress(com.zimbra.common.mime.InternetAddress ia, boolean nameFormatLastFirst)
/*     */   {
/*  88 */     this.nameFormatLastFirst = nameFormatLastFirst;
/*  89 */     initialize(ia.getAddress(), ia.getPersonal());
/*     */   }
/*     */   
/*     */   private void initialize(String email, String personal) {
/*  93 */     this.emailPart = email;
/*  94 */     this.personalPart = personal;
/*  95 */     if ("".equals(this.emailPart))
/*  96 */       this.emailPart = null;
/*  97 */     if (this.personalPart != null)
/*  98 */       this.personalPart = this.personalPart.trim().replaceAll("\\s+", " ");
/*     */   }
/*     */   
/*     */   public String getSortString() {
/* 102 */     parse();
/* 103 */     String sort = this.personalPart != null ? this.personalPart : this.emailPart;
/* 104 */     return sort != null ? sort : "";
/*     */   }
/*     */   
/*     */   public static String getSortString(List<ParsedAddress> addrs) {
/* 108 */     List<String> list = new ArrayList(addrs.size());
/* 109 */     for (ParsedAddress addr : addrs) {
/* 110 */       list.add(addr.getSortString());
/*     */     }
/* 112 */     return Joiner.on(", ").join(list);
/*     */   }
/*     */   
/*     */   public Map<String, String> getAttributes() {
/* 116 */     parse();
/* 117 */     HashMap<String, String> map = new HashMap();
/* 118 */     if (this.honorific != null) map.put(ContactConstants.A_namePrefix, this.honorific);
/* 119 */     if (this.firstName != null) map.put(ContactConstants.A_firstName, this.firstName);
/* 120 */     if (this.middleName != null) map.put(ContactConstants.A_middleName, this.middleName);
/* 121 */     if (this.lastName != null) map.put(ContactConstants.A_lastName, this.lastName);
/* 122 */     if (this.suffix != null) map.put(ContactConstants.A_nameSuffix, this.suffix);
/* 123 */     if (this.personalPart != null) map.put(ContactConstants.A_fullName, this.personalPart);
/* 124 */     if (this.emailPart != null) map.put(ContactConstants.A_email, this.emailPart);
/* 125 */     return map;
/*     */   }
/*     */   
/*     */   public ParsedAddress parse() {
/* 129 */     if (this.parsed) {
/* 130 */       return this;
/*     */     }
/*     */     
/* 133 */     if ((this.personalPart != null) && (this.personalPart.startsWith("\"")) && (this.personalPart.indexOf('"', 1) == this.personalPart.length() - 1)) {
/* 134 */       this.personalPart = this.personalPart.substring(1, this.personalPart.length() - 1).trim().replaceAll("\\s+", " ");
/*     */     }
/* 136 */     if ((this.personalPart != null) && (this.personalPart.equals(""))) {
/* 137 */       this.personalPart = null;
/*     */     }
/* 139 */     if ((this.emailPart != null) && (this.emailPart.equals(this.personalPart))) {
/* 140 */       this.personalPart = null;
/*     */     }
/* 142 */     if ((this.emailPart != null) && (this.personalPart == null)) {
/* 143 */       int p = this.emailPart.indexOf('@');
/* 144 */       String possible = (p == -1 ? this.emailPart : this.emailPart.substring(0, p)).replace('.', ' ').replace('_', ' ');
/* 145 */       if (possible.indexOf(' ') != -1) {
/* 146 */         this.personalPart = possible;
/*     */       } else {
/* 148 */         this.firstName = possible;
/*     */       }
/*     */     }
/* 151 */     if (this.personalPart != null) {
/* 152 */       List<NameToken> tokens = NameToken.tokenize(this.personalPart);
/*     */       
/*     */ 
/* 155 */       if (tokens.size() == 1) {
/* 156 */         this.firstName = ((NameToken)tokens.get(0)).toString();this.parsed = true;
/*     */       }
/*     */       
/* 159 */       if (!this.parsed)
/* 160 */         this.parsed = parseLastFirst(tokens);
/* 161 */       if (!this.parsed) {
/* 162 */         this.parsed = parseFirstLast(tokens);
/*     */       }
/* 164 */       if (!this.parsed) {
/* 165 */         for (NameToken token : tokens) {
/* 166 */           NameTokenType type = token.getType();
/* 167 */           if ((type == NameTokenType.ABBREVIATION) || (type == NameTokenType.INITIAL) || (type == NameTokenType.PREFIX) || (type == NameTokenType.TOKEN)) {
/* 168 */             this.firstName = token.toString();
/* 169 */             break;
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 175 */     this.parsed = true;
/* 176 */     return this;
/*     */   }
/*     */   
/*     */   private boolean parseLastFirst(List<NameToken> tokens)
/*     */   {
/* 181 */     int index = 0;int total = tokens.size();
/*     */     
/*     */ 
/* 184 */     int lstart = 0;int lend = index = readLastName(tokens, index);
/* 185 */     if (lend == lstart) {
/* 186 */       return false;
/*     */     }
/* 188 */     if ((index == 0) || (index >= total - 1) || (((NameToken)tokens.get(index++)).getType() != NameTokenType.COMMA)) {
/* 189 */       return false;
/*     */     }
/* 191 */     int hstart = index;int hend = index = readHonorific(tokens, index);
/*     */     
/* 193 */     int fstart = index;int fend = index = readFirstName(tokens, index, true);
/* 194 */     if (fend == fstart) {
/* 195 */       return false;
/*     */     }
/* 197 */     int mstart = index;int mend = index = readMiddleName(tokens, index);
/*     */     
/* 199 */     int suffixOffset = ((NameToken)tokens.get(index - 1)).getEndOffset();
/* 200 */     this.suffix = readSuffix(tokens, index);
/*     */     
/* 202 */     if (hstart != hend) this.honorific = StringUtil.join(" ", tokens.subList(hstart, hend));
/* 203 */     if (fstart != fend) this.firstName = StringUtil.join(" ", tokens.subList(fstart, fend));
/* 204 */     if (mstart != mend) this.middleName = StringUtil.join(" ", tokens.subList(mstart, mend));
/* 205 */     if (lstart != lend) { this.lastName = StringUtil.join(" ", tokens.subList(lstart, lend));
/*     */     }
/* 207 */     this.personalPart = (this.personalPart.substring(0, suffixOffset) + this.personalPart.substring(suffixOffset).replaceAll("\\\\", ""));
/*     */     
/* 209 */     return true;
/*     */   }
/*     */   
/*     */   private boolean parseFirstLast(List<NameToken> tokens)
/*     */   {
/* 214 */     int index = 0;int total = tokens.size();
/*     */     
/* 216 */     List<NameToken> mtokens = null;
/*     */     
/*     */ 
/*     */ 
/* 220 */     int hstart = 0;int hend = index = readHonorific(tokens, index);
/*     */     
/* 222 */     int fstart = index;int fend = index = readFirstName(tokens, index, false);
/*     */     
/* 224 */     int start = index;
/* 225 */     for (; index < total; index++) { NameTokenType type;
/* 226 */       if (((type = ((NameToken)tokens.get(index)).getType()) != NameTokenType.INITIAL) && (type != NameTokenType.ABBREVIATION) && (type != NameTokenType.PREFIX) && (type != NameTokenType.TOKEN))
/*     */         break;
/*     */     }
/* 229 */     for (; index > start; index--) {
/* 230 */       if (((NameToken)tokens.get(index - 1)).getType() != NameTokenType.ABBREVIATION)
/*     */         break;
/*     */     }
/* 233 */     if (start == index)
/* 234 */       return false;
/* 235 */     int lstart = index - 1;
/* 236 */     if (((NameToken)tokens.get(lstart)).getType() == NameTokenType.INITIAL)
/* 237 */       return false;
/* 238 */     for (; lstart > start; lstart--) {
/* 239 */       if (((NameToken)tokens.get(lstart - 1)).getType() != NameTokenType.PREFIX)
/*     */         break;
/*     */     }
/* 242 */     if (lstart > start)
/* 243 */       mtokens = tokens.subList(start, lstart);
/* 244 */     List<NameToken> ltokens = tokens.subList(lstart, index);
/*     */     
/* 246 */     int suffixOffset = ((NameToken)tokens.get(index - 1)).getEndOffset();
/* 247 */     this.suffix = readSuffix(tokens, index);
/*     */     
/* 249 */     if (hstart != hend) this.honorific = StringUtil.join(" ", tokens.subList(hstart, hend));
/* 250 */     if (mtokens != null) { this.middleName = StringUtil.join(" ", mtokens);
/*     */     }
/* 252 */     if (this.nameFormatLastFirst) {
/* 253 */       if (fstart != fend) this.lastName = StringUtil.join(" ", tokens.subList(fstart, fend));
/* 254 */       if (ltokens != null) this.firstName = StringUtil.join(" ", ltokens);
/*     */     } else {
/* 256 */       if (fstart != fend) this.firstName = StringUtil.join(" ", tokens.subList(fstart, fend));
/* 257 */       if (ltokens != null) { this.lastName = StringUtil.join(" ", ltokens);
/*     */       }
/*     */     }
/* 260 */     this.personalPart = (this.personalPart.substring(0, suffixOffset) + this.personalPart.substring(suffixOffset).replaceAll("\\\\", ""));
/*     */     
/* 262 */     return true;
/*     */   }
/*     */   
/*     */   private int readHonorific(List<NameToken> tokens, int index)
/*     */   {
/* 267 */     while ((index < tokens.size()) && (((NameToken)tokens.get(index)).getType() == NameTokenType.HONORIFIC))
/* 268 */       index++;
/* 269 */     return index;
/*     */   }
/*     */   
/*     */   private int readFirstName(List<NameToken> tokens, int index, boolean greedy)
/*     */   {
/* 274 */     int total = tokens.size();
/*     */     
/* 276 */     if (index >= total)
/* 277 */       return index;
/* 278 */     NameTokenType type; if (((type = ((NameToken)tokens.get(index)).getType()) == NameTokenType.ABBREVIATION) || (type == NameTokenType.TOKEN) || (type == NameTokenType.PREFIX))
/* 279 */       return index + 1;
/* 280 */     if (type != NameTokenType.INITIAL) {
/* 281 */       return index;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 295 */     index++;
/* 296 */     if (index >= (greedy ? total : total - 1))
/* 297 */       return index;
/* 298 */     switch (((NameToken)tokens.get(index)).getType()) {
/*     */     case INITIAL: 
/* 300 */       while ((index < total) && (((NameToken)tokens.get(index)).getType() == NameTokenType.INITIAL))
/* 301 */         index++;
/* 302 */       return index; case TOKEN:  NameTokenType type3;
/*     */       NameTokenType type3;
/* 304 */       return (greedy) || ((type3 = ((NameToken)tokens.get(index + 1)).getType()) == NameTokenType.TOKEN) || (type3 == NameTokenType.PREFIX) ? index + 1 : index;
/*     */     case PREFIX:  NameTokenType type3;
/* 306 */       return (greedy) && (index < total - 1) && ((type3 = ((NameToken)tokens.get(index + 1)).getType()) != NameTokenType.TOKEN) && (type3 != NameTokenType.PREFIX) ? index + 1 : index;
/*     */     }
/* 308 */     return index;
/*     */   }
/*     */   
/*     */   private int readMiddleName(List<NameToken> tokens, int index)
/*     */   {
/* 315 */     for (; 
/*     */         
/* 315 */         index < tokens.size(); index++) { NameTokenType type;
/* 316 */       if (((type = ((NameToken)tokens.get(index)).getType()) != NameTokenType.INITIAL) && (type != NameTokenType.ABBREVIATION) && (type != NameTokenType.PREFIX) && (type != NameTokenType.TOKEN))
/*     */         break;
/*     */     }
/* 319 */     return index;
/*     */   }
/*     */   
/*     */   private int readLastName(List<NameToken> tokens, int index)
/*     */   {
/* 325 */     for (; 
/* 325 */         index < tokens.size(); index++) { NameTokenType type;
/* 326 */       if ((type = ((NameToken)tokens.get(index)).getType()) != NameTokenType.PREFIX) {
/* 327 */         if (type != NameTokenType.TOKEN) break;
/* 328 */         index++; break;
/*     */       }
/*     */     }
/*     */     
/* 332 */     return index;
/*     */   }
/*     */   
/*     */   private String readSuffix(List<NameToken> tokens, int index)
/*     */   {
/* 337 */     int end = tokens.size();
/*     */     NameTokenType type;
/* 339 */     while ((index < end) && (((type = ((NameToken)tokens.get(index)).getType()) == NameTokenType.COMMA) || (type == NameTokenType.DELIMITER)))
/* 340 */       index++;
/* 341 */     NameTokenType type; while ((index < end) && (((type = ((NameToken)tokens.get(end - 1)).getType()) == NameTokenType.COMMA) || (type == NameTokenType.DELIMITER))) {
/* 342 */       end--;
/*     */     }
/* 344 */     if ((index < end) && (((NameToken)tokens.get(index)).getType() == NameTokenType.OPEN) && (((NameToken)tokens.get(end - 1)).getType() == NameTokenType.CLOSE)) {
/* 345 */       boolean parenthesized = true;
/* 346 */       for (int i = index + 1; (i < end - 1) && (parenthesized); i++) { NameTokenType type;
/* 347 */         if (((type = ((NameToken)tokens.get(i)).getType()) == NameTokenType.OPEN) || (type == NameTokenType.CLOSE))
/* 348 */           parenthesized = false;
/*     */       }
/* 350 */       if (parenthesized) {
/* 351 */         index++;end--;
/*     */       }
/*     */     }
/*     */     
/* 355 */     return index >= end ? null : this.personalPart.substring(((NameToken)tokens.get(index - 1)).getEndOffset(), ((NameToken)tokens.get(end - 1)).getEndOffset()).trim();
/*     */   }
/*     */   
/*     */   public int hashCode()
/*     */   {
/* 360 */     if (this.emailPart != null)
/* 361 */       return this.emailPart.hashCode();
/* 362 */     if (this.personalPart != null) {
/* 363 */       return this.personalPart.hashCode();
/*     */     }
/* 365 */     return 0;
/*     */   }
/*     */   
/*     */   public boolean equals(Object obj)
/*     */   {
/* 370 */     if (this == obj)
/* 371 */       return true;
/* 372 */     if ((obj == null) || (!(obj instanceof ParsedAddress))) {
/* 373 */       return false;
/*     */     }
/* 375 */     return compareTo((ParsedAddress)obj) == 0;
/*     */   }
/*     */   
/*     */   public int compareTo(ParsedAddress pa)
/*     */   {
/* 380 */     if ((this.emailPart != null) && (pa.emailPart != null))
/* 381 */       return this.emailPart.compareToIgnoreCase(pa.emailPart);
/* 382 */     if ((this.emailPart != null) && (pa.emailPart == null))
/* 383 */       return 1;
/* 384 */     if ((this.emailPart == null) && (pa.emailPart != null))
/* 385 */       return -1;
/* 386 */     if ((this.personalPart != null) && (pa.personalPart != null))
/* 387 */       return this.personalPart.compareToIgnoreCase(pa.personalPart);
/* 388 */     if ((this.personalPart != null) && (pa.personalPart == null))
/* 389 */       return 1;
/* 390 */     if ((this.personalPart == null) && (pa.personalPart != null)) {
/* 391 */       return -1;
/*     */     }
/* 393 */     return 0;
/*     */   }
/*     */   
/*     */   public String toString()
/*     */   {
/* 398 */     if (this.emailPart == null)
/* 399 */       return this.personalPart;
/* 400 */     if (this.personalPart == null) {
/* 401 */       return this.emailPart;
/*     */     }
/* 403 */     return '"' + this.personalPart + "\" <" + this.emailPart + '>';
/*     */   }
/*     */   
/*     */   private static enum NameTokenType {
/* 407 */     TOKEN,  PREFIX,  INITIAL,  HONORIFIC,  ABBREVIATION,  NUMERAL,  COMMA,  OPEN,  CLOSE,  DELIMITER;
/*     */     
/*     */     private NameTokenType() {}
/*     */   }
/*     */   
/*     */   private static class NameToken { private ParsedAddress.NameTokenType mType;
/*     */     private String mValue;
/*     */     private int mEndOffset;
/*     */     
/* 416 */     private NameToken(char delimiter, int start) { this.mValue = ("" + delimiter);
/* 417 */       this.mEndOffset = (start + 1);
/*     */       
/* 419 */       if (delimiter == ',') {
/* 420 */         this.mType = ParsedAddress.NameTokenType.COMMA;
/* 421 */       } else if ((delimiter == '(') || (delimiter == '[') || (delimiter == '【')) {
/* 422 */         this.mType = ParsedAddress.NameTokenType.OPEN;
/* 423 */       } else if ((delimiter == ')') || (delimiter == ']') || (delimiter == '】')) {
/* 424 */         this.mType = ParsedAddress.NameTokenType.CLOSE;
/*     */       } else
/* 426 */         this.mType = ParsedAddress.NameTokenType.DELIMITER;
/*     */     }
/*     */     
/*     */     private NameToken(String token, int start) {
/* 430 */       int tstart = 0; for (int tend = token.length(); 
/*     */           
/* 432 */           (tstart < tend) && (token.charAt(tstart) == '\'') && (token.charAt(tend - 1) == '\''); 
/* 433 */           tend--) { tstart++;
/*     */       }
/*     */       char c;
/* 436 */       while ((tstart < tend) && ((!Character.isLetterOrDigit(c = token.charAt(tstart))) || (c == '-')) && (c != '\'')) { tstart++;
/*     */       }
/*     */       char c;
/* 439 */       while ((tstart < tend) && ((!Character.isLetterOrDigit(c = token.charAt(tend - 1))) || (c == '-')) && (c != '.') && (c != '\'') && ((tstart > 0) || (c != '!'))) { tend--;
/*     */       }
/*     */       
/* 442 */       boolean delimiter = tstart >= tend;
/*     */       
/* 444 */       this.mValue = (delimiter ? token : token.substring(tstart, tend));
/* 445 */       this.mEndOffset = (start + token.length());
/*     */       
/* 447 */       int length = token.length();
/* 448 */       if (delimiter) {
/* 449 */         this.mType = ParsedAddress.NameTokenType.DELIMITER;
/* 450 */       } else if (SURNAME_PREFIXES.contains(token.toLowerCase())) {
/* 451 */         this.mType = ParsedAddress.NameTokenType.PREFIX;
/* 452 */       } else if ((length <= 2) && ((length == 1) || (token.charAt(1) == '.')) && (Character.isLetter(token.charAt(0)))) {
/* 453 */         this.mType = ParsedAddress.NameTokenType.INITIAL;
/* 454 */       } else if (ROMAN_NUMERALS.contains(token)) {
/* 455 */         this.mType = ParsedAddress.NameTokenType.NUMERAL;
/* 456 */       } else if (isAbbreviation()) {
/* 457 */         this.mType = ParsedAddress.NameTokenType.ABBREVIATION;
/* 458 */       } else if ((length > 2) && (token.charAt(length - 1) == '.')) {
/* 459 */         this.mType = ParsedAddress.NameTokenType.HONORIFIC;
/*     */       } else
/* 461 */         this.mType = ParsedAddress.NameTokenType.TOKEN;
/*     */     }
/*     */     
/*     */     private boolean isAbbreviation() {
/* 465 */       if (this.mValue.length() % 2 == 1) {
/* 466 */         return false;
/*     */       }
/* 468 */       for (int i = 0; i < this.mValue.length(); i += 2) {
/* 469 */         if ((this.mValue.charAt(i + 1) != '.') || (!Character.isLetter(this.mValue.charAt(i))))
/* 470 */           return false;
/*     */       }
/* 472 */       return true;
/*     */     }
/*     */     
/* 475 */     private static final Set<String> SURNAME_PREFIXES = new HashSet(Arrays.asList(new String[] { "ab", "abu", "af", "al", "am", "an", "ap", "auf", "av", "bar", "ben", "bin", "da", "de", "degli", "dei", "del", "della", "de'", "delle", "dello", "den", "der", "di", "dos", "du", "el", "groot", "groote", "het", "ibn", "la", "las", "le", "lo", "los", "mac", "nÍ", "nic", "op", "ten", "ter", "toe", "van", "vande", "vander", "vom", "von", "zu", "zum", "zur", "'t", "Ó" }));
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 483 */     private static final Set<String> ROMAN_NUMERALS = new HashSet(Arrays.asList(new String[] { "II", "III", "IIII", "IV", "V", "VI", "VII", "VIII", "Jr" }));
/*     */     
/*     */ 
/*     */     ParsedAddress.NameTokenType getType()
/*     */     {
/* 488 */       return this.mType;
/*     */     }
/*     */     
/*     */     int getEndOffset() {
/* 492 */       return this.mEndOffset;
/*     */     }
/*     */     
/*     */     public String toString()
/*     */     {
/* 497 */       return this.mValue;
/*     */     }
/*     */     
/* 500 */     private static final Set<Character> TOKEN_DELIMITERS = new HashSet(Arrays.asList(new Character[] { Character.valueOf(','), Character.valueOf(';'), Character.valueOf('/'), Character.valueOf(':'), Character.valueOf('('), Character.valueOf(')'), Character.valueOf('['), Character.valueOf(']'), Character.valueOf('【'), Character.valueOf('】') }));
/*     */     
/*     */ 
/*     */     static List<NameToken> tokenize(String raw)
/*     */     {
/* 505 */       if (raw == null) {
/* 506 */         return null;
/*     */       }
/* 508 */       raw = raw.trim().replaceAll("\\s+", " ");
/* 509 */       int start = 0;int index = 0;int length = raw.length();
/* 510 */       List<NameToken> tokens = new ArrayList(6);
/*     */       do {
/* 512 */         start = index;
/* 513 */         for (; index < length; 
/*     */             
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 527 */             goto 226)
/*     */         {
/* 514 */           char c = raw.charAt(index++);
/* 515 */           boolean delimiter = (TOKEN_DELIMITERS.contains(Character.valueOf(c))) || (c == '\\') || (c == '"') || (Character.isWhitespace(c));
/*     */           
/* 517 */           if ((delimiter) || (index >= length))
/*     */           {
/* 519 */             if (raw.charAt(start) == '-') {
/* 520 */               tokens.add(new NameToken('-', start++));
/*     */             }
/* 522 */             int end = delimiter ? index - 1 : index;
/* 523 */             if (end > start) {
/* 524 */               tokens.add(new NameToken(raw.substring(start, end), start));
/*     */             }
/* 526 */             if (!TOKEN_DELIMITERS.contains(Character.valueOf(c))) break;
/* 527 */             tokens.add(new NameToken(c, index - 1));
/*     */           }
/*     */         }
/*     */         
/* 531 */         while ((index < length) && (Character.isWhitespace(raw.charAt(index))))
/* 532 */           index++;
/* 533 */       } while (index < length);
/*     */       
/* 535 */       return tokens;
/*     */     }
/*     */     
/*     */     static String asTokenString(List<NameToken> tokens)
/*     */     {
/* 540 */       StringBuilder sb = new StringBuilder();
/* 541 */       for (NameToken token : tokens)
/* 542 */         sb.append(sb.length() == 0 ? "[" : ", ").append(token.getType());
/* 543 */       return ']';
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mime/ParsedAddress.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */